//! import "common\Base.j"
//! import "common\Tree.j"

library SpellBookPatch initializer Init requires Base, Tree

//! runtextmacro TreeSimple("integer", "SpellTable")

globals
	private integer Top = 0
	private unit array Unit
	private integer array Skill
	private integer array Level
	private integer array Next

	private integer array Spells
	private integer SpellTop = 0

	private integer lastAbility = 0
	private boolean loadAbility = false
endglobals

private function HookAddAbility takes unit u, integer id returns nothing
	set lastAbility = id
endfunction

private function HookSetAbilityLevelTo takes unit u, integer id, integer from, integer to returns nothing
	if loadAbility then
		return
	endif
	if id == lastAbility then
		return
	endif
	if from != 1 then
		return
	endif
	if to < 2 then
		return
	endif
	call SpellTable.Insert(id)
endfunction

private function HookAddAbilityBJ takes integer id, unit u returns nothing
	call HookAddAbility(u, id)
endfunction

private function HookSetAbilityLevel takes unit u, integer id, integer level returns nothing
	call HookSetAbilityLevelTo(u, id, GetUnitAbilityLevel(u, id), level)
endfunction

private function HookSetAbilityLevelBJ takes integer id, unit u, integer level returns nothing
	call HookSetAbilityLevel(u, id, level)
endfunction

private function HookIncAbilityLevel takes unit u, integer id returns nothing
	local integer level = GetUnitAbilityLevel(u, id)
	call HookSetAbilityLevelTo(u, id, level, level + 1)
endfunction

private function HookIncAbilityLevelBJ takes integer id, unit u returns nothing
	call HookIncAbilityLevel(u, id)
endfunction

hook UnitAddAbility HookAddAbility
hook UnitAddAbilityBJ HookAddAbilityBJ
hook SetUnitAbilityLevel HookSetAbilityLevel
hook SetUnitAbilityLevelSwapped HookSetAbilityLevelBJ
hook IncUnitAbilityLevel HookIncAbilityLevel
hook IncUnitAbilityLevelSwapped HookIncAbilityLevelBJ

private function Clear takes nothing returns nothing
	loop
		exitwhen Top == 0
		set Top = Top - 1
		set Unit[Top] = null
	endloop
endfunction

private function SetUnitSpellBookLevel takes nothing returns boolean
	local unit u = GetFilterUnit()
	local integer i = 0
	local integer id
	local integer level
	loop
		exitwhen i == SpellTop
		set id = Spells[i]
		set level = GetUnitAbilityLevel(u, id)
		if level > 1 then
			if Top > GetArrayMaxSize() then
				call Error()
				return false
			endif
			set Unit[Top] = u
			set Skill[Top] = id
			set Level[Top] = level
			set Top = Top + 1
		endif
		set i = i + 1
	endloop
	set u = null
	return false
endfunction

private function SavePlayer takes player p returns nothing
    call GroupEnumUnitsOfPlayer(TempGroup, p, Condition(function SetUnitSpellBookLevel))
endfunction

private function Save takes nothing returns boolean
	local integer i
	set SpellTop = 0
	set i = SpellTable.GetFirst()
	loop
		exitwhen i == 0
		set Spells[SpellTop] = SpellTable.Get(i)
		set SpellTop = SpellTop + 1
		set i = SpellTable.GetNext(i)
	endloop
	call Clear()
	set i = 0
	loop
		exitwhen i == bj_MAX_PLAYER_SLOTS
		call SavePlayer.evaluate(Player(i))
		set i = i + 1
	endloop
	call TimerStart(CreateTimer(), 0, false, function Clear)
	return false
endfunction

private function Load takes nothing returns boolean
	local integer i = 0
	loop
		exitwhen i == Top
		call SetUnitAbilityLevel(Unit[i], Skill[i], Level[i])
		set i = i + 1
	endloop
	return false
endfunction

private function Init takes nothing returns nothing
	local trigger t
	set t = CreateTrigger()
	call TriggerAddCondition(t, Condition(function Save))
	call TriggerRegisterGameEvent(t, EVENT_GAME_SAVE)
	call TriggerRegisterTimerEvent(t, 60., true)
	set t = CreateTrigger()
	call TriggerAddCondition(t, Condition(function Load))
	call TriggerRegisterGameEvent(t, EVENT_GAME_LOADED)
	set t = null
endfunction

endlibrary